/*
 * Camera
 *
 */

/*
typedef struct
{
        float *	look;
        float *	up;
	float * right;
        float *	position;
	float	RotatedX;
	float	RotatedY;
	float	RotatedZ;
} Camera_t;
*/

#include "Camera.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>


/*
 *---------------------------------------------------------------------------------------------------------------
 */

int normalizeVector3D(float * e)
{
        float magnitude = sqrtf(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);

        e[0] /= magnitude;
        e[1] /= magnitude;
        e[2] /= magnitude;

        return 0;
}

int cross(float *  vector1, float * vector2, float * result)
{
        //calculate the i,j,k coefficients of the cross product 
        float x = vector1[1]*vector2[2]-vector2[1]*vector1[2];
        float y = vector1[0]*vector2[2]-vector2[0]*vector1[2];
        float z = vector1[0]*vector2[1]-vector2[0]*vector1[1];
        result[0] = x;
        result[1] = y;
        result[2] = z;

        return 0;
}

/*
 *---------------------------------------------------------------------------------------------------------------
 */

void Camera_Init(Camera_t * camera) //inits the values (Position: (0|0|0) Target: (0|0|-1) )
{
	camera->look 	= (float*) malloc(3*sizeof(float));
	camera->up 	= (float*) malloc(3*sizeof(float));
	camera->right	= (float*) malloc(3*sizeof(float));
	camera->position= (float*) malloc(3*sizeof(float));

	camera->look[0]  	= 0.0; camera->look[1] 		= 0.0; camera->look[2] 		= -1.0;
	camera->up[0] 	 	= 0.0; camera->up[1] 		= 1.0; camera->up[2] 		= 0.0;
	camera->right[0] 	= 1.0; camera->right[1] 	= 0.0; camera->right[2] 	= 0.0;
	camera->position[0] 	= 0.0; camera->position[1] 	= 0.0; camera->position[2] 	= 0.0;
	cross(camera->look,camera->up, camera->right);
	normalizeVector3D(camera->right);

	fprintf(stdout, "Camera look(%f,%f,%f) up (%f,%f,%f) right(%f,%f,%f)\n",camera->look[0],camera->look[1],camera->look[2],camera->up[0],camera->up[1],camera->up[2],camera->right[0],camera->right[1],camera->right[2]);

	camera->RotatedX =  camera->RotatedY =  camera->RotatedZ = 0.0;
}

void Camera_Destroy(Camera_t camera)
{
	free(camera.look);
	free(camera.up);
	free(camera.right);
	free(camera.position);
}
//	void Render ( void );	//executes some glRotates and a glTranslate command
				//Note: You should call glLoadIdentity before using Render

void Move(Camera_t * camera, float * Direction)
{
	camera->position[0] += Direction[0];
	camera->position[1] += Direction[1];
	camera->position[2] += Direction[2];

}

void RotateX(Camera_t * camera, float Angle)
{

	float  sPI180 = sin(Angle*(M_PI/180.0)); 
	float  cPI180 = cos(Angle*(M_PI/180.0)); 
	
	 camera->RotatedX += Angle;

	//Rotate viewdir around the right vector:
	camera->look[0] = camera->look[0]*cPI180 + camera->up[0]*sPI180;
	camera->look[0] = camera->look[1]*cPI180 + camera->up[1]*sPI180;
	camera->look[0] = camera->look[2]*cPI180 + camera->up[2]*sPI180;
	normalizeVector3D(camera->look);

	//now compute the new UpVector (by cross product)
	cross(camera->look,camera->right, camera->up);
	camera->up[0] *=-1.0;
	camera->up[1] *=-1.0;
	camera->up[2] *=-1.0;

}

void RotateY(Camera_t * camera, float Angle)
{
        float  sPI180 = sin(Angle*(M_PI/180.0));
        float  cPI180 = cos(Angle*(M_PI/180.0));

	 camera->RotatedY += Angle;

	//Rotate viewdir around the up vector:
	camera->look[0] = camera->look[0]*cPI180 - camera->right[0]*sPI180;
        camera->look[0] = camera->look[1]*cPI180 - camera->right[1]*sPI180;
        camera->look[0] = camera->look[2]*cPI180 - camera->right[2]*sPI180;
	normalizeVector3D(camera->look);

	//now compute the new RightVector (by cross product)
	cross(camera->look,camera->up, camera->right);
}

void RotateZ(Camera_t * camera, float Angle)
{

        float  sPI180 = sin(Angle*(M_PI/180.0));
        float  cPI180 = cos(Angle*(M_PI/180.0));

	camera->RotatedZ += Angle;

	//Rotate viewdir around the right vector:
        camera->right[0] = camera->right[0]*cPI180 + camera->up[0]*sPI180;
        camera->right[1] = camera->right[1]*cPI180 + camera->up[1]*sPI180;
        camera->right[2] = camera->right[2]*cPI180 + camera->up[2]*sPI180;
        normalizeVector3D(camera->right);

	//now compute the new UpVector (by cross product)
	cross(camera->look,camera->right, camera->up);
        camera->up[0] *=-1.0;
        camera->up[1] *=-1.0;
        camera->up[2] *=-1.0;
}

void MoveForward(Camera_t * camera, float Distance)
{
	camera->position[0] += camera->look[0]*(-Distance);
        camera->position[1] += camera->look[1]*(-Distance);
        camera->position[2] += camera->look[2]*(-Distance);
}

void MoveUpward(Camera_t * camera, float Distance)
{
	camera->position[0] += camera->right[0]*(Distance);
        camera->position[1] += camera->right[1]*(Distance);
        camera->position[2] += camera->right[2]*(Distance);
}

void StrafeRight(Camera_t * camera, float Distance)
{
	camera->position[0] += camera->up[0]*(Distance);
        camera->position[1] += camera->up[1]*(Distance);
        camera->position[2] += camera->up[2]*(Distance);
}
